from xtquant import xtdata
import time
import pandas as pd
import numpy as np
from datetime import datetime, timedelta
from typing import Dict, List, Tuple, Optional


class MACDConfig:
    """
    MACD性能配置类
    
    重要说明：
    - 推荐使用历史分钟数据初始化（模拟同花顺/东方财富），无需预热
    - 历史初始化可在开盘后立即获得准确MACD，无需等待17分钟
    - 原理：用前几天的1分钟K线数据计算EMA初始值，当日数据接续计算
    """

    # 基础配置（仅在使用tick预热模式时生效）
    USE_WARMUP = False  # 是否使用tick预热数据（不推荐，建议使用历史分钟数据初始化）
    PREFER_PREVIOUS_DAY_TICKS = True  # 优先使用前一天的tick数据作为预热数据
    WARMUP_DAYS = 6  # 预热数据天数
    WARMUP_HOURS = 4  # 预热数据小时数

    # 性能优化配置
    TICK_CHECK_INTERVAL = 1  # 每N个tick检查一次MACD
    CACHE_TTL = 30  # MACD结果缓存有效期（秒）
    MAX_CACHE_SIZE = 300  # 最大缓存条目数

    # 计算参数
    FAST_EMA = 12  # 快线EMA周期
    SLOW_EMA = 26 # 慢线EMA周期
    SIGNAL_EMA = 9  # 信号线EMA周期
    CROSS_EPSILON = 1e-5  # 金叉/死叉判定容差，防止0附近抖动。想更稳：把CROSS_EPSILON调大一点（如5e-6或1e-5），把MIN_CROSS_GAP_BARS设为2~3。
    MIN_CROSS_GAP_BARS = 5  # 两次交叉最少间隔bar数，防止连续抖动重复判定

    # 信号检测配置
    SIGNAL_TIME_WINDOW = 300  # 信号检测时间窗口（秒）
    MIN_DATA_POINTS = 50  # 最小数据点要求

    # 输出控制
    LOG_LEVEL = "INFO"  # 日志级别：DEBUG, INFO, WARNING, ERROR
    ENABLE_DETAILED_LOGGING = False  # 是否启用详细日志

    # 资源限制
    MAX_CONCURRENT_CALCULATIONS = 3  # 最大并发计算数
    CALCULATION_TIMEOUT = 30  # 计算超时时间（秒）

    @classmethod
    def get_optimized_params(cls):
        """获取优化后的参数配置"""
        return {
            'use_warmup': cls.USE_WARMUP,
            'prefer_previous_day_ticks': cls.PREFER_PREVIOUS_DAY_TICKS,
            'warmup_days': cls.WARMUP_DAYS,
            'warmup_hours': cls.WARMUP_HOURS,
            'fast_ema': cls.FAST_EMA,
            'slow_ema': cls.SLOW_EMA,
            'signal_ema': cls.SIGNAL_EMA,
            'cache_ttl': cls.CACHE_TTL,
            'max_cache_size': cls.MAX_CACHE_SIZE
        }

    @classmethod
    def should_check_macd(cls, tick_count: int) -> bool:
        """判断是否应该检查MACD"""
        return tick_count % cls.TICK_CHECK_INTERVAL == 0

    @classmethod
    def is_cache_valid(cls, last_check_time: float, current_time: float) -> bool:
        """判断缓存是否有效"""
        return (current_time - last_check_time) < cls.CACHE_TTL

    @classmethod
    def get_signal_window(cls) -> int:
        """获取信号检测时间窗口"""
        return cls.SIGNAL_TIME_WINDOW


# 缓存管理配置
class CacheConfig:
    """缓存管理配置"""

    ENABLE_CACHE = True
    CACHE_CLEANUP_INTERVAL = 300  # 缓存清理间隔（秒）
    CACHE_STATS_LOG_INTERVAL = 600  # 缓存统计日志间隔（秒）

    @classmethod
    def should_use_cache(cls) -> bool:
        """是否应该使用缓存"""
        return cls.ENABLE_CACHE

    @classmethod
    def get_cache_config(cls):
        """获取缓存配置"""
        return {
            'enable_cache': cls.ENABLE_CACHE,
            'cleanup_interval': cls.CACHE_CLEANUP_INTERVAL,
            'stats_log_interval': cls.CACHE_STATS_LOG_INTERVAL
        }


##MACD信号计算器类
class MACDSignalCalculator:

    def __init__(self, xtdata, use_warmup: bool = True):
        """
        初始化MACD信号计算器

        Args:
            use_warmup: 是否使用预热数据，默认True
        """
        self.use_warmup = use_warmup
        self.xtdata = xtdata

    ##获取前一天的tick数据用于预热
    def get_previous_day_ticks_for_warmup(self, stock_code: str) -> Optional[pd.DataFrame]:
        """
        获取前一天的tick数据用于预热，只取下午1点到3点的数据

        Args:
            stock_code: 股票代码

        Returns:
            过滤后的前一天下午tick数据DataFrame
        """
        try:
            # 获取前一个交易日的日期（如果是周一则获取上周五）
            today = datetime.now()
            if today.weekday() == 0:  # 周一
                # 获取上周五的日期
                yesterday = (today - timedelta(days=3)).strftime("%Y%m%d")
            else:
                # 获取前一天的日期
                yesterday = (today - timedelta(days=1)).strftime("%Y%m%d")

            # 下载前一天的tick数据
            self.xtdata.download_history_data(stock_code=stock_code, period="tick",
                                              start_time=yesterday, end_time=yesterday)
            time.sleep(2)

            # 获取本地数据
            data = self.xtdata.get_local_data(stock_list=[stock_code], period='tick',
                                              start_time=yesterday, end_time=yesterday)

            if not data or stock_code not in data:
                return None

            df = data[stock_code]
            if df.empty:
                return None

            # 确定时间列和价格列
            time_col = next((col for col in df.columns if 'time' in col.lower()), None)
            price_col = next((col for col in ['price', 'lastPrice', 'close', 'last', 'current']
                              if col in df.columns), None)

            if not time_col or not price_col:
                return None

            # 转换时间戳
            try:
                if df[time_col].dtype in ['int64', 'float64']:
                    df['time'] = pd.to_datetime(df[time_col], unit='ms') + pd.Timedelta(hours=8)
                else:
                    df['time'] = pd.to_datetime(df[time_col], format='%Y%m%d%H%M%S', errors='coerce')

                df = df[df['time'].notna()].sort_values('time')
                if df.empty:
                    return None
            except Exception:
                return None

            # 过滤无效价格数据
            df_filtered = df[df[price_col] > 0].copy()
            if df_filtered.empty:
                return None

            df_filtered['time_only'] = df_filtered['time'].dt.time

            # 只保留交易时间的数据作为预热数据：9:30-11:30 和 13:00-15:00
            morning_start = pd.Timestamp('09:30:00').time()
            morning_end = pd.Timestamp('11:30:00').time()
            afternoon_start = pd.Timestamp('13:00:00').time()
            afternoon_end = pd.Timestamp('15:00:00').time()

            df_filtered = df_filtered[
                ((df_filtered['time_only'] >= morning_start) & (df_filtered['time_only'] <= morning_end)) |
                ((df_filtered['time_only'] >= afternoon_start) & (df_filtered['time_only'] <= afternoon_end))
                ]

            # 调试信息：显示预热数据的时间范围
            if not df_filtered.empty:
                print(
                    f"预热数据时间范围: {df_filtered['time'].min().strftime('%H:%M')} 到 {df_filtered['time'].max().strftime('%H:%M')}")
                print(f"预热数据点数量: {len(df_filtered)}")
                print("预热数据包含: 9:30-11:30 和 13:00-15:00 交易时间")

            if df_filtered.empty:
                return None

            # 只保留必要的列
            result_df = df_filtered[['time', price_col]].copy()
            result_df.rename(columns={price_col: 'close'}, inplace=True)

            return result_df

        except Exception as e:
            print(f"获取前一天tick数据失败: {e}")
            return None

    ##获取前N天的分钟线数据用于EMA初始化（正确方法：模拟同花顺/东方财富）
    def get_historical_minutes_for_ema_init(self, stock_code: str, days: int = 5) -> Optional[pd.DataFrame]:
        """
        获取历史分钟线数据用于EMA初始化
        同花顺/东方财富的真实做法：使用前几天的分钟级数据计算EMA初始值
        
        重要：对于日内分钟级MACD，必须用分钟级历史数据，不能用日线！
        """
        try:
            today = datetime.now()
            if today.weekday() == 0:  # 周一
                end_date = (today - timedelta(days=3)).strftime("%Y%m%d")
            else:
                end_date = (today - timedelta(days=1)).strftime("%Y%m%d")

            # 获取前N天的数据（对于EMA17，需要至少17*2=34个交易日的分钟数据，但5-10天通常够用）
            start_date = (today - timedelta(days=days + 10)).strftime("%Y%m%d")

            print(f"正在获取历史分钟数据: {start_date} ~ {end_date}")
            
            # 下载1分钟K线数据
            self.xtdata.download_history_data(stock_code=stock_code, period="1m", 
                                            start_time=start_date, end_time=end_date)
            time.sleep(2)

            # 获取本地1分钟数据
            data = self.xtdata.get_local_data(stock_list=[stock_code], period='1m', 
                                            start_time=start_date, end_time=end_date)
            if data and stock_code in data:
                df = data[stock_code]
                if not df.empty and 'close' in df.columns:
                    # 过滤掉集合竞价和午休时间
                    df = self._filter_trading_hours(df)
                    return df
            return None
        except Exception as e:
            print(f"获取历史分钟数据失败: {e}")
            return None
    
    def _filter_trading_hours(self, df: pd.DataFrame, include_auction: bool = False) -> pd.DataFrame:
        """
        过滤出交易时间的数据
        
        Args:
            include_auction: 是否包含集合竞价时间（9:15-9:25）
        """
        if df.empty:
            return df
            
        # 确保有时间索引
        if not isinstance(df.index, pd.DatetimeIndex):
            return df
            
        # 创建时间列用于过滤
        df_copy = df.copy()
        df_copy['time_only'] = df_copy.index.time
        
        if include_auction:
            # 包含集合竞价：9:15-11:30 和 13:00-15:00
            morning_start = pd.Timestamp('09:15:00').time()
            morning_end = pd.Timestamp('11:30:00').time()
        else:
            # 不包含集合竞价：9:30-11:30 和 13:00-15:00
            morning_start = pd.Timestamp('09:30:00').time()
            morning_end = pd.Timestamp('11:30:00').time()
            
        afternoon_start = pd.Timestamp('13:00:00').time()
        afternoon_end = pd.Timestamp('15:00:00').time()
        
        # 过滤
        df_filtered = df_copy[
            ((df_copy['time_only'] >= morning_start) & (df_copy['time_only'] <= morning_end)) |
            ((df_copy['time_only'] >= afternoon_start) & (df_copy['time_only'] <= afternoon_end))
        ]
        
        return df_filtered.drop('time_only', axis=1)
    
    ##获取前一日最后N分钟的数据（实验B用）
    def get_previous_day_last_minutes(self, stock_code: str, minutes: int = 30) -> Optional[pd.DataFrame]:
        """
        获取前一个交易日最后N分钟的分钟数据
        用于实验B：前一日部分数据预热
        """
        try:
            today = datetime.now()
            if today.weekday() == 0:  # 周一
                yesterday = (today - timedelta(days=3)).strftime("%Y%m%d")
            else:
                yesterday = (today - timedelta(days=1)).strftime("%Y%m%d")
            
            print(f"正在获取昨天最后{minutes}分钟数据...")
            
            self.xtdata.download_history_data(stock_code=stock_code, period="1m", 
                                            start_time=yesterday, end_time=yesterday)
            time.sleep(2)
            
            data = self.xtdata.get_local_data(stock_list=[stock_code], period='1m', 
                                            start_time=yesterday, end_time=yesterday)
            
            if data and stock_code in data:
                df = data[stock_code]
                if not df.empty and 'close' in df.columns:
                    # 过滤交易时间
                    df = self._filter_trading_hours(df, include_auction=False)
                    # 取最后N分钟
                    df_last = df.tail(minutes)
                    print(f"  ✓ 获取到昨天最后{len(df_last)}分钟数据")
                    return df_last
            return None
        except Exception as e:
            print(f"  ✗ 获取昨天数据失败: {e}")
            return None

    ##生成预热数据，模拟开盘前的价格波动（保留原有方法作为备选）
    def generate_warmup_data(self, latest_close: float, warmup_hours: int = 2) -> pd.DataFrame:
        # 从8:00开始，每5分钟一个数据点
        warmup_points = warmup_hours * 12  # 2小时 * 12个5分钟点

        # 基于最新收盘价生成预热数据
        base_price = latest_close

        # 生成时间序列（从8:00开始）
        start_time = datetime.now().replace(hour=8, minute=0, second=0, microsecond=0)
        warmup_times = [start_time + timedelta(minutes=5 * i) for i in range(warmup_points)]

        # 生成价格数据（模拟小幅波动）
        np.random.seed(42)  # 固定随机种子，确保可重现
        price_changes = np.random.normal(0, base_price * 0.001, warmup_points)  # 0.1%的标准差
        warmup_prices = [base_price + change for change in price_changes]

        # 创建预热数据DataFrame
        warmup_df = pd.DataFrame({
            'time': warmup_times,
            'price': warmup_prices,
            'open': warmup_prices,
            'high': [p * (1 + abs(np.random.normal(0, 0.0005))) for p in warmup_prices],
            'low': [p * (1 - abs(np.random.normal(0, 0.0005))) for p in warmup_prices],
            'close': warmup_prices,
            'volume': [int(np.random.uniform(100, 1000)) for _ in range(warmup_points)]
        })

        return warmup_df

    ##计算历史分钟数据的EMA初始值（模拟同花顺/东方财富）
    def calculate_ema_seed_from_history(self, historical_df: pd.DataFrame, period: int) -> float:
        """
        使用历史分钟数据计算EMA的初始值
        这是同花顺/东方财富能在开盘后立即显示准确MACD的关键
        
        重要：对于日内MACD，这里的period是分钟数（如8分钟、17分钟）
        """
        if historical_df is None or historical_df.empty:
            return None
            
        close_prices = historical_df['close'].values
        if len(close_prices) < period:
            print(f"  警告：历史数据不足 ({len(close_prices)} < {period})，EMA初始化可能不准确")
            # 数据不足时，仍然尝试计算
            
        # 计算EMA：从历史分钟数据开始完整计算
        alpha = 2 / (period + 1)
        ema = close_prices[0]
        
        for price in close_prices[1:]:
            ema = alpha * price + (1 - alpha) * ema
            
        return ema

    ##支持历史EMA初始化的EMA计算（改进版）
    def enhanced_ema_with_history_init(self, series: pd.Series, period: int,
                                      ema_seed: Optional[float] = None) -> pd.Series:
        """
        使用历史EMA初始值计算当日EMA
        ema_seed: 从历史日线数据计算出的EMA初始值
        """
        if not isinstance(series, pd.Series):
            series = pd.Series(series)

        # 使用历史EMA种子值初始化
        if ema_seed is not None:
            initial_ema = ema_seed
        else:
            # 无历史数据，使用第一个值
            initial_ema = series.iloc[0]

        # 计算EMA
        alpha = 2 / (period + 1)
        ema_values = [initial_ema]

        for price in series:
            new_ema = alpha * price + (1 - alpha) * ema_values[-1]
            ema_values.append(new_ema)

        # 返回EMA值（去掉初始值）
        return pd.Series(ema_values[1:], index=series.index)

    ##支持预热数据的EMA计算，实现热启动（保留兼容）
    def enhanced_ema_with_warmup(self, series: pd.Series, period: int,
                                 warmup_data: Optional[pd.DataFrame] = None) -> pd.Series:
        if not isinstance(series, pd.Series):
            series = pd.Series(series)

        if warmup_data is not None and not warmup_data.empty:
            # 使用预热数据初始化EMA
            warmup_series = warmup_data['close'] if 'close' in warmup_data.columns else warmup_data['price']
            if len(warmup_series) >= period:
                # 从预热数据计算初始EMA值
                initial_ema = warmup_series.tail(period).mean()
                # 从预热数据的最后一个值开始计算
                last_warmup_price = warmup_series.iloc[-1]
            else:
                # 预热数据不足，使用简单平均
                initial_ema = warmup_series.mean() if not warmup_series.empty else series.iloc[0]
                last_warmup_price = initial_ema
        else:
            # 无预热数据，使用传统方法
            initial_ema = series.iloc[0]
            last_warmup_price = initial_ema

        # 计算EMA
        alpha = 2 / (period + 1)
        ema_values = [initial_ema]

        for price in series:
            new_ema = alpha * price + (1 - alpha) * ema_values[-1]
            ema_values.append(new_ema)

        # 返回EMA值（去掉初始值）
        return pd.Series(ema_values[1:], index=series.index)

    ##支持预热数据的MACD计算，实现热启动"
    def enhanced_calculate_macd(self, prices: pd.Series, fast: int = 12, slow: int = 26, signal: int = 9,
                                warmup_data: Optional[pd.DataFrame] = None) -> Tuple[pd.Series, pd.Series, pd.Series]:
        if not isinstance(prices, pd.Series):
            prices = pd.Series(prices)

        # 确保为float并使用顺序索引
        series = prices.astype(float).reset_index(drop=True)

        # 使用增强版EMA计算
        ema_short = self.enhanced_ema_with_warmup(series, fast, warmup_data)
        ema_slow = self.enhanced_ema_with_warmup(series, slow, warmup_data)

        # 计算DIFF
        diff = ema_short - ema_slow

        # 使用DIFF计算DEA（信号线）
        if warmup_data is not None and not warmup_data.empty:
            # 如果有预热数据，使用预热数据计算预热DIFF来初始化DEA
            # 确定预热数据的价格列
            warmup_price_col = next((col for col in ['close', 'price'] if col in warmup_data.columns), None)
            if warmup_price_col and len(warmup_data[warmup_price_col]) >= max(fast, slow):
                # 计算预热数据的EMA
                warmup_ema_short = self.enhanced_ema_with_warmup(warmup_data[warmup_price_col], fast)
                warmup_ema_slow = self.enhanced_ema_with_warmup(warmup_data[warmup_price_col], slow)
                # 计算预热数据的DIFF
                warmup_diff_series = warmup_ema_short - warmup_ema_slow
                # 使用预热数据DIFF的最后一个值来初始化DEA
                warmup_diff_last = warmup_diff_series.iloc[-1] if not warmup_diff_series.empty else 0
            else:
                warmup_diff_last = 0

            # 使用预热DIFF的最后一个值来初始化DEA计算
            dea = self.enhanced_ema_with_warmup(diff, signal, pd.DataFrame({'close': [warmup_diff_last]}))
        else:
            dea = self.enhanced_ema_with_warmup(diff, signal)

        # 计算MACD柱状图
        macd_histogram = 2 * (diff - dea)

        return diff, dea, macd_histogram

    ##将tick数据重新采样为分钟数据
    def resample_ticks_to_minutes(self, df: pd.DataFrame, price_col: str = 'price') -> pd.DataFrame:
        if 'time' not in df.columns:
            return pd.DataFrame()

        df_resampled = df.set_index('time')
        df_minutes = df_resampled[price_col].resample('1min').agg({
            'open': 'first',
            'high': 'max',
            'low': 'min',
            'close': 'last',
            'volume': 'sum' if 'volume' in df_resampled.columns else lambda x: len(x)
        }).dropna()
        return df_minutes.reset_index()

    ##下载并获取tick数据
    def get_segment_ticks(self, stock_code: str) -> Optional[Dict[str, pd.DataFrame]]:
        today = datetime.now().strftime("%Y%m%d")
        # today = "20250811"
        self.xtdata.download_history_data(stock_code=stock_code, period="tick", start_time=today, end_time=today)
        time.sleep(2)

        try:
            data = self.xtdata.get_local_data(stock_list=[stock_code], period='tick', start_time=today, end_time=today)
            return data if data and stock_code in data else None
        except Exception:
            return None

    ##实验方法：三种不同的MACD计算方式
    def calculate_macd_experimental(self, prices: pd.Series, fast: int = 12, slow: int = 26, signal: int = 9,
                                   experiment_mode: str = 'A',
                                   warmup_data: Optional[pd.DataFrame] = None,
                                   verbose: bool = False) -> Tuple[pd.Series, pd.Series, pd.Series]:
        """
        实验性MACD计算，支持三种模式：
        
        实验A：使用集合竞价，第一个EMA = 第一个收盘价（同花顺方法）
        实验B：使用前一日30分钟数据预热
        实验C：使用SMA初始化EMA
        
        Args:
            verbose: 是否输出详细信息（实时监控时应设为False）
        """
        if not isinstance(prices, pd.Series):
            prices = pd.Series(prices)
        series = prices.astype(float).reset_index(drop=True)
        
        def calc_ema_mode_a(data, period):
            """实验A：第一个EMA = 第一个收盘价（同花顺方法）"""
            alpha = 2 / (period + 1)
            ema = np.zeros(len(data))
            ema[0] = data[0]  # 第一个EMA = 第一个收盘价
            for i in range(1, len(data)):
                ema[i] = alpha * data[i] + (1 - alpha) * ema[i-1]
            return ema
        
        def calc_ema_mode_c(data, period):
            """实验C：使用SMA初始化EMA"""
            alpha = 2 / (period + 1)
            ema = np.zeros(len(data))
            
            if len(data) >= period:
                # 用前period个数据的平均值作为初始EMA
                ema[period-1] = np.mean(data[:period])
                for i in range(period, len(data)):
                    ema[i] = alpha * data[i] + (1 - alpha) * ema[i-1]
                # 前period-1个设为NaN
                ema[:period-1] = np.nan
            else:
                ema[0] = data[0]
                for i in range(1, len(data)):
                    ema[i] = alpha * data[i] + (1 - alpha) * ema[i-1]
            
            return ema
        
        if experiment_mode == 'A':
            if verbose:
                print("  使用实验A：集合竞价开始，第一个EMA=第一个收盘价")
            # 直接从当日数据开始计算（同花顺方法）
            ema_fast = calc_ema_mode_a(series.values, fast)
            ema_slow = calc_ema_mode_a(series.values, slow)
            diff = ema_fast - ema_slow
            dea = calc_ema_mode_a(diff, signal)
            
        elif experiment_mode == 'B':
            if verbose:
                print("  使用实验B：前一日30分钟数据预热")
            if warmup_data is not None and not warmup_data.empty:
                # 合并预热数据和当日数据
                warmup_close = warmup_data['close'].values
                combined = np.concatenate([warmup_close, series.values])
                
                # 连续计算
                ema_fast_full = calc_ema_mode_a(combined, fast)
                ema_slow_full = calc_ema_mode_a(combined, slow)
                diff_full = ema_fast_full - ema_slow_full
                dea_full = calc_ema_mode_a(diff_full, signal)
                
                # 只取当日部分
                warmup_len = len(warmup_close)
                diff = diff_full[warmup_len:]
                dea = dea_full[warmup_len:]
            else:
                if verbose:
                    print("  警告：未提供预热数据，降级为实验A")
                ema_fast = calc_ema_mode_a(series.values, fast)
                ema_slow = calc_ema_mode_a(series.values, slow)
                diff = ema_fast - ema_slow
                dea = calc_ema_mode_a(diff, signal)
        
        elif experiment_mode == 'C':
            if verbose:
                print("  使用实验C：SMA初始化EMA")
            ema_fast = calc_ema_mode_c(series.values, fast)
            ema_slow = calc_ema_mode_c(series.values, slow)
            diff = ema_fast - ema_slow
            
            # 对DIFF也用SMA初始化
            diff_valid = diff[~np.isnan(diff)]
            if len(diff_valid) >= signal:
                dea_temp = calc_ema_mode_c(diff_valid, signal)
                # 重新对齐到原始索引
                dea = np.full(len(diff), np.nan)
                valid_idx = np.where(~np.isnan(diff))[0]
                dea[valid_idx] = dea_temp
            else:
                dea = np.full(len(diff), np.nan)
        
        # 转为Series
        diff_series = pd.Series(diff, index=series.index)
        dea_series = pd.Series(dea, index=series.index)
        macd = 2 * (diff_series - dea_series)
        
        return diff_series, dea_series, macd
    
    ##改进的MACD计算函数（支持历史EMA初始化 - 模拟同花顺/东方财富）
    def calculate_macd(self, prices: pd.Series, fast: int = 12, slow: int = 26, signal: int = 9,
                       warmup_data: Optional[pd.DataFrame] = None,
                       historical_df: Optional[pd.DataFrame] = None,
                       use_continuous_calc: bool = True) -> Tuple[pd.Series, pd.Series, pd.Series]:
        """
        计算MACD，支持多种初始化方式：
        1. historical_df + use_continuous_calc=True: 历史数据和当日数据合并连续计算（最推荐）
        2. historical_df + use_continuous_calc=False: 使用历史EMA种子值初始化
        3. warmup_data: 使用tick预热数据初始化（备选）
        """
        if not isinstance(prices, pd.Series):
            prices = pd.Series(prices)
        series = prices.astype(float).reset_index(drop=True)

        # 优先使用历史分钟数据初始化EMA（同花顺/东方财富的方法）
        if historical_df is not None and not historical_df.empty:
            
            if use_continuous_calc:
                # 方法1：连续计算法（推荐）- 将历史数据和当日数据合并后统一计算
                print("  使用连续计算法（历史+当日数据合并计算）")
                
                # 合并历史数据和当日数据
                hist_close = historical_df['close'].values
                combined_prices = np.concatenate([hist_close, series.values])
                
                # 计算完整的EMA
                def calc_ema(data, period):
                    alpha = 2 / (period + 1)
                    ema_values = np.zeros(len(data))
                    ema_values[0] = data[0]
                    for i in range(1, len(data)):
                        ema_values[i] = alpha * data[i] + (1 - alpha) * ema_values[i - 1]
                    return ema_values
                
                # 计算快慢线
                ema_fast_full = calc_ema(combined_prices, fast)
                ema_slow_full = calc_ema(combined_prices, slow)
                
                # 计算DIFF
                diff_full = ema_fast_full - ema_slow_full
                
                # 计算DEA（对DIFF做EMA）
                dea_full = calc_ema(diff_full, signal)
                
                # 只取当日部分
                hist_len = len(hist_close)
                diff = pd.Series(diff_full[hist_len:], index=series.index)
                dea = pd.Series(dea_full[hist_len:], index=series.index)
                
            else:
                # 方法2：种子值法 - 从历史数据计算种子值
                print("  使用种子值法（历史数据计算初始EMA）")
                fast_seed = self.calculate_ema_seed_from_history(historical_df, fast)
                slow_seed = self.calculate_ema_seed_from_history(historical_df, slow)
                
                # 使用种子值计算当日EMA
                ema_short = self.enhanced_ema_with_history_init(series, fast, fast_seed)
                ema_slow = self.enhanced_ema_with_history_init(series, slow, slow_seed)
                
                # 计算DIFF
                diff = ema_short - ema_slow
                
                # 计算DEA的种子值
                hist_close = historical_df['close'].values
                alpha_fast = 2 / (fast + 1)
                alpha_slow = 2 / (slow + 1)
                
                hist_fast_ema = hist_close[0]
                hist_slow_ema = hist_close[0]
                
                for price in hist_close[1:]:
                    hist_fast_ema = alpha_fast * price + (1 - alpha_fast) * hist_fast_ema
                    hist_slow_ema = alpha_slow * price + (1 - alpha_slow) * hist_slow_ema
                
                hist_diff = hist_fast_ema - hist_slow_ema
                dea = self.enhanced_ema_with_history_init(diff, signal, hist_diff)
            
        elif warmup_data is not None and not warmup_data.empty:
            # 使用tick预热数据（备选方案）
            return self.enhanced_calculate_macd(prices, fast, slow, signal, warmup_data)
        else:
            # 无任何初始化数据，使用传统方法（不推荐，早盘数据会不准）
            def ths_ema(series_in: pd.Series, period: int) -> pd.Series:
                if len(series_in) < period:
                    return pd.Series([np.nan] * len(series_in), index=series_in.index)
                ema = series_in.astype(float).copy()
                ema.iloc[: period - 1] = np.nan
                sma_init = series_in.iloc[:period].mean()
                ema.iloc[period - 1] = sma_init
                alpha = 2 / (period + 1)
                for i in range(period, len(series_in)):
                    ema.iloc[i] = alpha * series_in.iloc[i] + (1 - alpha) * ema.iloc[i - 1]
                return ema

            ema_short = ths_ema(series, fast)
            ema_slow = ths_ema(series, slow)
            diff = ema_short - ema_slow
            valid_diff = diff.dropna()
            if len(valid_diff) < signal:
                dea_full = pd.Series([np.nan] * len(series))
                macd_full = pd.Series([np.nan] * len(series))
                return diff, dea_full, macd_full
            dea = ths_ema(valid_diff, signal)
            dea_full = pd.Series([np.nan] * len(series))
            dea_full.iloc[dea.index] = dea.values
            macd_valid = 2 * (valid_diff.loc[dea.index] - dea)
            macd_full = pd.Series([np.nan] * len(series))
            macd_full.iloc[macd_valid.index] = macd_valid.values
            return diff, dea_full, macd_full

        # 计算MACD柱状图
        macd_histogram = 2 * (diff - dea)
        return diff, dea, macd_histogram

    ##检测MACD金叉死叉信号并返回结果（使用同花顺方法）
    def detect_macd_signals(self, stock_code: str, fast: int = 12, slow: int = 26, signal: int = 9,
                            include_auction: bool = True,
                            use_simple_init: bool = True) -> Dict[str, List[Dict[str, any]]]:
        """
        检测MACD金叉死叉信号并返回结果
        
        ⭐ 默认使用同花顺方法：从集合竞价开始，第一个EMA = 第一个收盘价

        Args:
            stock_code: 股票代码
            include_auction: 是否包含集合竞价数据（9:15-9:25），默认True
            use_simple_init: 是否使用简单初始化（第一个EMA=第一个收盘价），默认True（同花顺方法）

        Returns:
            包含金叉和死叉信号的字典，格式如下：
            {
                'golden_cross': [{'time': '2024-01-01 09:30:00', 'price': 10.5}, ...],
                'death_cross': [{'time': '2024-01-01 10:15:00', 'price': 10.3}, ...],
                'latest_macd': {'diff': 0.001, 'dea': -0.002, 'macd': 0.006, 'trend': 'bullish'},
                'data_info': {'total_minutes': 240, 'time_range': '09:15-15:00'}
            }
        """
        # 获取tick数据
        ticks = self.get_segment_ticks(stock_code)
        if not ticks or stock_code not in ticks:
            return {
                'golden_cross': [],
                'death_cross': [],
                'latest_macd': {},
                'data_info': {}
            }

        df = ticks[stock_code]
        if df.empty:
            return {
                'golden_cross': [],
                'death_cross': [],
                'latest_macd': {},
                'data_info': {}
            }

        # 使用同花顺方法：简单初始化，不需要历史数据
        # 注：在实时环境中不打印，避免影响性能

        # 确定价格列
        price_col = next((col for col in ['price', 'lastPrice', 'close', 'last', 'current'] if col in df.columns), None)
        if not price_col:
            return {
                'golden_cross': [],
                'death_cross': [],
                'latest_macd': {},
                'data_info': {}
            }

        # 转换时间戳
        time_col = next((col for col in df.columns if 'time' in col.lower()), None)
        if not time_col:
            return {
                'golden_cross': [],
                'death_cross': [],
                'latest_macd': {},
                'data_info': {}
            }

        try:
            if df[time_col].dtype in ['int64', 'float64']:
                df['time'] = pd.to_datetime(df[time_col], unit='ms') + pd.Timedelta(hours=8)
            else:
                df['time'] = pd.to_datetime(df[time_col], format='%Y%m%d%H%M%S', errors='coerce')

            df = df[df['time'].notna()].sort_values('time')
            if df.empty:
                return {
                    'golden_cross': [],
                    'death_cross': [],
                    'latest_macd': {},
                    'data_info': {}
                }
        except Exception:
            return {
                'golden_cross': [],
                'death_cross': [],
                'latest_macd': {},
                'data_info': {}
            }

        # 过滤无效数据和午休时间
        df_filtered = df[df[price_col] > 0].copy()
        df_filtered['time_only'] = df_filtered['time'].dt.time

        # 去除午休时间 (11:30-13:00)
        lunch_start = pd.Timestamp('11:30:00').time()
        lunch_end = pd.Timestamp('13:00:00').time()

        if include_auction:
            # 包含集合竞价：保留 9:15-11:30 和 13:00-15:00
            morning_start = pd.Timestamp('09:15:00').time()
            morning_end = pd.Timestamp('11:30:00').time()
            afternoon_start = pd.Timestamp('13:00:00').time()
            afternoon_end = pd.Timestamp('15:00:00').time()
            
            df_filtered = df_filtered[
                ((df_filtered['time_only'] >= morning_start) & (df_filtered['time_only'] <= morning_end)) |
                ((df_filtered['time_only'] >= afternoon_start) & (df_filtered['time_only'] <= afternoon_end))
            ]
        else:
            # 不包含集合竞价：保留 9:30-11:30 和 13:00-15:00
            morning_start = pd.Timestamp('09:30:00').time()
            morning_end = pd.Timestamp('11:30:00').time()
            afternoon_start = pd.Timestamp('13:00:00').time()
            afternoon_end = pd.Timestamp('15:00:00').time()
            
            df_filtered = df_filtered[
                ((df_filtered['time_only'] >= morning_start) & (df_filtered['time_only'] <= morning_end)) |
                ((df_filtered['time_only'] >= afternoon_start) & (df_filtered['time_only'] <= afternoon_end))
            ]

        if df_filtered.empty:
            return {
                'golden_cross': [],
                'death_cross': [],
                'latest_macd': {},
                'data_info': {}
            }

        # 重新采样为分钟数据
        df_minutes = self.resample_ticks_to_minutes(df_filtered, price_col)
        if df_minutes.empty:
            return {
                'golden_cross': [],
                'death_cross': [],
                'latest_macd': {},
                'data_info': {}
            }

        # 计算MACD（静默模式，实时环境不打印）
        if use_simple_init:
            # 使用同花顺方法：简单初始化（实验A）
            macd_line, signal_line, histogram = self.calculate_macd_experimental(
                df_minutes['close'],
                fast=fast,
                slow=slow,
                signal=signal,
                experiment_mode='A',
                verbose=False  # 实时环境静默运行
            )
        else:
            # 使用历史数据初始化方法（非同花顺）
            macd_line, signal_line, histogram = self.calculate_macd(
                df_minutes['close'], 
                fast=fast, 
                slow=slow, 
                signal=signal
            )

        # 检测金叉死叉（鲁棒版，加入容差与斜率确认，避免0附近抖动导致反向提示）
        delta = macd_line - signal_line  # DIF - DEA
        eps = getattr(MACDConfig, 'CROSS_EPSILON', 1e-6)
        min_gap = max(0, int(getattr(MACDConfig, 'MIN_CROSS_GAP_BARS', 1)))

        prev_delta = delta.shift(1)
        delta_change = delta - prev_delta

        # 容差符号：> eps 为正，< -eps 为负，其余视为 0（交汇/近似交汇）
        sign_prev = (prev_delta > eps).astype(int) - (prev_delta < -eps).astype(int)
        sign_now = (delta > eps).astype(int) - (delta < -eps).astype(int)

        # 在存在0的边界时，用斜率来确认方向（只在一侧为0时触发）
        cross_up_mask = (
                ((sign_prev < 0) & (sign_now > 0)) |
                ((sign_prev < 0) & (sign_now == 0) & (delta_change > 0)) |
                ((sign_prev == 0) & (sign_now > 0) & (delta_change > 0))
        )

        cross_down_mask = (
                ((sign_prev > 0) & (sign_now < 0)) |
                ((sign_prev > 0) & (sign_now == 0) & (delta_change < 0)) |
                ((sign_prev == 0) & (sign_now < 0) & (delta_change < 0))
        )

        # 去抖动：限制交叉最小间隔（按bar计）
        def thin_cross(mask_series, min_gap_bars):
            idx = mask_series[mask_series.fillna(False)].index.to_list()
            if not idx:
                return mask_series
            kept = []
            last_kept = None
            for i in idx:
                if last_kept is None or (i - last_kept) >= min_gap_bars:
                    kept.append(i)
                    last_kept = i
            new_mask = mask_series.copy()
            new_mask[:] = False
            new_mask.loc[kept] = True
            return new_mask

        if min_gap > 1:
            cross_up_mask = thin_cross(cross_up_mask, min_gap)
            cross_down_mask = thin_cross(cross_down_mask, min_gap)

        # 构建金叉信号数组
        golden_cross = []
        cross_up_times = df_minutes.loc[cross_up_mask.fillna(False), 'time']
        for t in cross_up_times:
            if pd.isna(t):
                continue
            time_str = pd.to_datetime(t).strftime('%Y-%m-%d %H:%M:%S')
            price_at_time = df_minutes.loc[df_minutes['time'] == t, 'close'].iloc[0] if not df_minutes[
                df_minutes['time'] == t].empty else 0
            golden_cross.append({
                'time': time_str,
                'price': float(price_at_time)
            })

        # 构建死叉信号数组
        death_cross = []
        cross_down_times = df_minutes.loc[cross_down_mask.fillna(False), 'time']
        for t in cross_down_times:
            if pd.isna(t):
                continue
            time_str = pd.to_datetime(t).strftime('%Y-%m-%d %H:%M:%S')
            price_at_time = df_minutes.loc[df_minutes['time'] == t, 'close'].iloc[0] if not df_minutes[
                df_minutes['time'] == t].empty else 0
            death_cross.append({
                'time': time_str,
                'price': float(price_at_time)
            })

        # 构建最新MACD信息（只在有有效数值时返回，避免 NaN 输出）
        latest_macd = {}
        try:
            if not macd_line.empty and not signal_line.empty:
                valid_mask = macd_line.notna() & signal_line.notna()
                if valid_mask.any():
                    last_idx = macd_line[valid_mask].index[-1]
                    latest_diff = macd_line.loc[last_idx]
                    latest_dea = signal_line.loc[last_idx]
                    if not histogram.empty and last_idx in histogram.index and not pd.isna(histogram.loc[last_idx]):
                        latest_histogram = histogram.loc[last_idx]
                    else:
                        latest_histogram = 2 * (latest_diff - latest_dea)

                    latest_macd = {
                        'diff': float(latest_diff),
                        'dea': float(latest_dea),
                        'macd': float(latest_histogram),
                        'trend': 'bullish' if latest_diff > latest_dea else 'bearish'
                    }
        except Exception:
            latest_macd = {}

        # 构建数据信息
        data_info = {
            'total_minutes': len(df_minutes),
            'time_range': f"{df_minutes['time'].min().strftime('%H:%M')}-{df_minutes['time'].max().strftime('%H:%M')}"
        }

        return {
            'golden_cross': golden_cross,
            'death_cross': death_cross,
            'latest_macd': latest_macd,
            'data_info': data_info
        }


# 使用示例
if __name__ == "__main__" and False:
    # 创建数据提供者

    # 创建MACD信号计算器实例（不使用tick预热，使用历史日线初始化）
    calculator = MACDSignalCalculator(xtdata, use_warmup=False)

    # 测试股票代码
    stock_code = "513310.SH"
    print("=" * 80)
    print(f"测试股票代码: {stock_code}")
    print(f"MACD参数配置: 快线={MACDConfig.FAST_EMA}, 慢线={MACDConfig.SLOW_EMA}, 信号线={MACDConfig.SIGNAL_EMA}")
    print("=" * 80)

    # 测试历史分钟数据获取（模拟同花顺/东方财富的方法）
    print("\n=== 测试历史分钟数据初始化（同花顺/东方财富方法） ===")
    historical_data = calculator.get_historical_minutes_for_ema_init(stock_code, days=5)
    if historical_data is not None and not historical_data.empty:
        print(f"✓ 成功获取历史分钟数据: {len(historical_data)} 条")
        print(f"  时间范围: {historical_data.index[0]} 到 {historical_data.index[-1]}")
        print(f"  收盘价范围: {historical_data['close'].min():.2f} ~ {historical_data['close'].max():.2f}")
        
        # 计算并显示EMA初始值
        fast_seed = calculator.calculate_ema_seed_from_history(historical_data, MACDConfig.FAST_EMA)
        slow_seed = calculator.calculate_ema_seed_from_history(historical_data, MACDConfig.SLOW_EMA)
        print(f"  EMA初始值: 快线={fast_seed:.4f}, 慢线={slow_seed:.4f}")
    else:
        print("✗ 获取历史分钟数据失败")

    # 旧的调用方式（已弃用）
    print("\n=== 计算MACD信号（历史分钟数据连续计算法） ===")
    signals = calculator.detect_macd_signals(
        stock_code, 
        include_auction=True,
        use_simple_init=False  # 使用历史数据方法
    )

    # 输出结果
    print("\n" + "=" * 80)
    print(f"股票代码: {stock_code}")
    print(f"数据信息: {signals['data_info']}")
    print(f"金叉信号数量: {len(signals['golden_cross'])}")
    print(f"死叉信号数量: {len(signals['death_cross'])}")
    print("=" * 80)

    if signals['golden_cross']:
        print("\n【金叉信号】（做多信号）")
        for i, signal in enumerate(signals['golden_cross'], 1):
            print(f"  {i}. 时间: {signal['time']}, 价格: {signal['price']:.4f}")

    if signals['death_cross']:
        print("\n【死叉信号】（做空信号）")
        for i, signal in enumerate(signals['death_cross'], 1):
            print(f"  {i}. 时间: {signal['time']}, 价格: {signal['price']:.4f}")

    if signals['latest_macd']:
        print(f"\n【最新MACD值】")
        print(f"  DIFF (快线-慢线): {signals['latest_macd']['diff']:.6f}")
        print(f"  DEA  (信号线):    {signals['latest_macd']['dea']:.6f}")
        print(f"  MACD (柱状图):    {signals['latest_macd']['macd']:.6f}")
        print(f"  当前趋势: {'🔴 多头' if signals['latest_macd']['trend'] == 'bullish' else '🟢 空头'}")
    
    print("\n" + "=" * 80)
    print("说明：")
    print("1. 本程序使用【历史分钟数据初始化EMA】方法，模拟同花顺/东方财富")
    print("2. 优点：开盘后即可获得准确MACD，无需等待17分钟")
    print("3. 原理：用前几天的分钟K线计算EMA初始值，今日数据接续计算")
    print("4. 对比方法：请在同花顺/东方财富查看相同股票的1分钟MACD金叉死叉点")
    print("5. 如果信号时间一致，说明算法准确")
    print("=" * 80)


# 三种实验对比测试
def run_experiments_comparison(stock_code: str = "159605.SZ"):
    """
    运行三种实验方法的对比测试
    
    实验A：使用集合竞价，第一个EMA = 第一个收盘价
    实验B：使用前一日30分钟数据预热  
    实验C：使用SMA初始化EMA
    """
    print("\n" + "=" * 80)
    print("三种实验方法对比测试")
    print("=" * 80)
    print(f"测试股票：{stock_code}")
    print(f"MACD参数：快线={MACDConfig.FAST_EMA}, 慢线={MACDConfig.SLOW_EMA}, 信号线={MACDConfig.SIGNAL_EMA}")
    print("=" * 80)
    
    calculator = MACDSignalCalculator(xtdata, use_warmup=False)
    
    # 获取今日tick数据
    print("\n正在获取今日数据...")
    ticks = calculator.get_segment_ticks(stock_code)
    if not ticks or stock_code not in ticks:
        print("❌ 获取今日数据失败")
        return
    
    df = ticks[stock_code]
    if df.empty:
        print("❌ 今日数据为空")
        return
    
    # 处理时间和价格列
    price_col = next((col for col in ['price', 'lastPrice', 'close', 'last', 'current'] if col in df.columns), None)
    time_col = next((col for col in df.columns if 'time' in col.lower()), None)
    
    if not price_col or not time_col:
        print("❌ 数据列不完整")
        return
    
    # 转换时间
    if df[time_col].dtype in ['int64', 'float64']:
        df['time'] = pd.to_datetime(df[time_col], unit='ms') + pd.Timedelta(hours=8)
    else:
        df['time'] = pd.to_datetime(df[time_col], format='%Y%m%d%H%M%S', errors='coerce')
    
    df = df[df['time'].notna()].sort_values('time')
    df_filtered = df[df[price_col] > 0].copy()
    
    print(f"✓ 获取到今日数据 {len(df_filtered)} 个tick")
    
    # 准备三种实验的数据
    results = {}
    
    # ==================== 实验A：集合竞价开始 ====================
    print("\n" + "=" * 80)
    print("实验A：使用集合竞价数据，第一个EMA = 第一个收盘价")
    print("=" * 80)
    
    # 包含集合竞价时间（9:15开始）
    df_a = df_filtered.copy()
    df_a['time_only'] = df_a['time'].dt.time
    
    # 从9:15开始（包含集合竞价）
    auction_start = pd.Timestamp('09:15:00').time()
    morning_end = pd.Timestamp('11:30:00').time()
    afternoon_start = pd.Timestamp('13:00:00').time()
    afternoon_end = pd.Timestamp('15:00:00').time()
    
    df_a = df_a[
        ((df_a['time_only'] >= auction_start) & (df_a['time_only'] <= morning_end)) |
        ((df_a['time_only'] >= afternoon_start) & (df_a['time_only'] <= afternoon_end))
    ]
    
    df_minutes_a = calculator.resample_ticks_to_minutes(df_a, price_col)
    print(f"  数据点数：{len(df_minutes_a)} 分钟（含集合竞价）")
    print(f"  时间范围：{df_minutes_a['time'].min().strftime('%H:%M')} - {df_minutes_a['time'].max().strftime('%H:%M')}")
    print(f"  第一个收盘价：{df_minutes_a['close'].iloc[0]:.4f}")
    
    diff_a, dea_a, macd_a = calculator.calculate_macd_experimental(
        df_minutes_a['close'],
        fast=MACDConfig.FAST_EMA,
        slow=MACDConfig.SLOW_EMA,
        signal=MACDConfig.SIGNAL_EMA,
        experiment_mode='A',
        verbose=True  # 测试时输出详细信息
    )
    results['A'] = (df_minutes_a, diff_a, dea_a, macd_a)
    
    # ==================== 实验B：前一日30分钟预热 ====================
    print("\n" + "=" * 80)
    print("实验B：使用前一日最后30分钟数据预热")
    print("=" * 80)
    
    # 获取昨天最后30分钟
    warmup_df_b = calculator.get_previous_day_last_minutes(stock_code, minutes=30)
    
    # 今天从9:15开始
    df_minutes_b = df_minutes_a.copy()
    
    if warmup_df_b is not None:
        print(f"  预热数据：{len(warmup_df_b)} 分钟")
        print(f"  今日数据：{len(df_minutes_b)} 分钟")
    else:
        warmup_df_b = pd.DataFrame()
        print("  ⚠️ 未获取到预热数据，将使用实验A方法")
    
    diff_b, dea_b, macd_b = calculator.calculate_macd_experimental(
        df_minutes_b['close'],
        fast=MACDConfig.FAST_EMA,
        slow=MACDConfig.SLOW_EMA,
        signal=MACDConfig.SIGNAL_EMA,
        experiment_mode='B',
        warmup_data=warmup_df_b,
        verbose=True  # 测试时输出详细信息
    )
    results['B'] = (df_minutes_b, diff_b, dea_b, macd_b)
    
    # ==================== 实验C：SMA初始化 ====================
    print("\n" + "=" * 80)
    print("实验C：使用SMA初始化EMA")
    print("=" * 80)
    
    df_minutes_c = df_minutes_a.copy()
    print(f"  数据点数：{len(df_minutes_c)} 分钟")
    print(f"  SMA计算：前{MACDConfig.FAST_EMA}个和{MACDConfig.SLOW_EMA}个数据的平均值")
    
    diff_c, dea_c, macd_c = calculator.calculate_macd_experimental(
        df_minutes_c['close'],
        fast=MACDConfig.FAST_EMA,
        slow=MACDConfig.SLOW_EMA,
        signal=MACDConfig.SIGNAL_EMA,
        experiment_mode='C',
        verbose=True  # 测试时输出详细信息
    )
    results['C'] = (df_minutes_c, diff_c, dea_c, macd_c)
    
    # ==================== 对比结果 ====================
    print("\n" + "=" * 80)
    print("前10分钟MACD值对比（用于与同花顺对比）")
    print("=" * 80)
    
    for exp_name, (df_min, diff, dea, macd) in results.items():
        print(f"\n实验{exp_name}:")
        print(f"{'时间':<10} {'收盘价':<10} {'DIFF':<12} {'DEA':<12} {'MACD':<12}")
        print("-" * 65)
        
        for i in range(min(10, len(df_min))):
            if i < len(diff) and not pd.isna(diff.iloc[i]) and not pd.isna(dea.iloc[i]):
                time_str = df_min['time'].iloc[i].strftime('%H:%M')
                close_val = df_min['close'].iloc[i]
                diff_val = diff.iloc[i]
                dea_val = dea.iloc[i]
                macd_val = macd.iloc[i]
                print(f"{time_str:<10} {close_val:<10.4f} {diff_val:<12.6f} {dea_val:<12.6f} {macd_val:<12.6f}")
    
    # 检测金叉死叉
    print("\n" + "=" * 80)
    print("金叉死叉信号对比")
    print("=" * 80)
    
    for exp_name, (df_min, diff, dea, macd) in results.items():
        print(f"\n实验{exp_name}:")
        
        delta = diff - dea
        delta_prev = delta.shift(1)
        
        # 金叉：DIFF上穿DEA
        golden_mask = (delta_prev < 0) & (delta > 0)
        # 死叉：DIFF下穿DEA  
        death_mask = (delta_prev > 0) & (delta < 0)
        
        golden_times = df_min.loc[golden_mask.fillna(False), 'time']
        death_times = df_min.loc[death_mask.fillna(False), 'time']
        
        if len(golden_times) > 0:
            print(f"  金叉: {[t.strftime('%H:%M') for t in golden_times]}")
        else:
            print(f"  金叉: 无")
            
        if len(death_times) > 0:
            print(f"  死叉: {[t.strftime('%H:%M') for t in death_times]}")
        else:
            print(f"  死叉: 无")
    
    print("\n" + "=" * 80)
    print("对比建议：")
    print("1. 在同花顺打开 {} 的1分钟K线".format(stock_code))
    print("2. 设置MACD参数为 (8, 17, 9)")
    print("3. 对比前10分钟的DIFF、DEA、MACD数值")
    print("4. 查看金叉死叉时间点是否一致")
    print("5. 哪个实验方法最接近同花顺，就使用哪个方法")
    print("=" * 80)


if __name__ == "__main__" and False:  # 设为False，让原来的示例不运行
    # 原来的示例代码
    pass


# ========== 主程序：使用同花顺方法 ==========
if __name__ == "__main__":
    print("=" * 80)
    print("MACD 金叉死叉检测 - 同花顺算法")
    print("=" * 80)
    
    # 创建计算器
    calculator = MACDSignalCalculator(xtdata, use_warmup=False)
    
    # 测试股票
    stock_code = "513050.SH"
    
    # 使用同花顺方法检测信号
    # include_auction=True: 包含集合竞价（9:15开始）
    # use_simple_init=True: 使用简单初始化（第一个EMA=第一个收盘价）
    signals = calculator.detect_macd_signals(
        stock_code,
        include_auction=True,    # ⭐ 包含集合竞价
        use_simple_init=True     # ⭐ 使用同花顺方法
    )
    
    # 输出结果
    print("\n" + "=" * 80)
    print(f"股票代码: {stock_code}")
    print(f"数据信息: {signals['data_info']}")
    print(f"金叉信号数量: {len(signals['golden_cross'])}")
    print(f"死叉信号数量: {len(signals['death_cross'])}")
    print("=" * 80)

    if signals['golden_cross']:
        print("\n【金叉信号】（做多信号）")
        for i, signal in enumerate(signals['golden_cross'], 1):
            print(f"  {i}. 时间: {signal['time']}, 价格: {signal['price']:.4f}")

    if signals['death_cross']:
        print("\n【死叉信号】（做空信号）")
        for i, signal in enumerate(signals['death_cross'], 1):
            print(f"  {i}. 时间: {signal['time']}, 价格: {signal['price']:.4f}")

    if signals['latest_macd']:
        print(f"\n【最新MACD值】")
        print(f"  DIFF (快线-慢线): {signals['latest_macd']['diff']:.6f}")
        print(f"  DEA  (信号线):    {signals['latest_macd']['dea']:.6f}")
        print(f"  MACD (柱状图):    {signals['latest_macd']['macd']:.6f}")
        print(f"  当前趋势: {'🔴 多头' if signals['latest_macd']['trend'] == 'bullish' else '🟢 空头'}")
    
    print("\n" + "=" * 80)
    print("✅ 使用同花顺算法：")
    print("   1. 包含集合竞价数据（9:15-9:25）")
    print("   2. 第一个EMA = 第一个收盘价")
    print("   3. 无需历史数据预热")
    print("   4. 开盘后立即获得准确MACD")
    print("=" * 80)
    
    print("\n如需运行三种实验对比，请调用：")
    print("run_experiments_comparison(stock_code='513090.SH')")
    print("=" * 80)